home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / snd_mix.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  10KB  |  505 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // snd_mix.c -- portable code to mix sounds for snd_dma.c
  21.  
  22. #include "quakedef.h"
  23.  
  24. #ifdef _WIN32
  25. #include "winquake.h"
  26. #else
  27. #define DWORD    unsigned long
  28. #endif
  29.  
  30. #define    PAINTBUFFER_SIZE    512
  31. portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
  32. int        snd_scaletable[32][256];
  33. int     *snd_p, snd_linear_count, snd_vol;
  34. short    *snd_out;
  35.  
  36. void Snd_WriteLinearBlastStereo16 (void);
  37.  
  38. #if    !id386
  39. void Snd_WriteLinearBlastStereo16 (void)
  40. {
  41.     int        i;
  42.     int        val;
  43.  
  44.     for (i=0 ; i<snd_linear_count ; i+=2)
  45.     {
  46.         val = (snd_p[i]*snd_vol)>>8;
  47.         if (val > 0x7fff)
  48.             snd_out[i] = 0x7fff;
  49.         else if (val < (short)0x8000)
  50.             snd_out[i] = (short)0x8000;
  51.         else
  52.             snd_out[i] = val;
  53.  
  54.         val = (snd_p[i+1]*snd_vol)>>8;
  55.         if (val > 0x7fff)
  56.             snd_out[i+1] = 0x7fff;
  57.         else if (val < (short)0x8000)
  58.             snd_out[i+1] = (short)0x8000;
  59.         else
  60.             snd_out[i+1] = val;
  61.     }
  62. }
  63. #endif
  64.  
  65. void S_TransferStereo16 (int endtime)
  66. {
  67.     int        lpos;
  68.     int        lpaintedtime;
  69.     DWORD    *pbuf;
  70. #ifdef _WIN32
  71.     int        reps;
  72.     DWORD    dwSize,dwSize2;
  73.     DWORD    *pbuf2;
  74.     HRESULT    hresult;
  75. #endif
  76.     
  77.     snd_vol = volume.value*256;
  78.  
  79.     snd_p = (int *) paintbuffer;
  80.     lpaintedtime = paintedtime;
  81.  
  82. #ifdef _WIN32
  83.     if (pDSBuf)
  84.     {
  85.         reps = 0;
  86.  
  87.         while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
  88.                                        &pbuf2, &dwSize2, 0)) != DS_OK)
  89.         {
  90.             if (hresult != DSERR_BUFFERLOST)
  91.             {
  92.                 Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
  93.                 S_Shutdown ();
  94.                 S_Startup ();
  95.                 return;
  96.             }
  97.  
  98.             if (++reps > 10000)
  99.             {
  100.                 Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
  101.                 S_Shutdown ();
  102.                 S_Startup ();
  103.                 return;
  104.             }
  105.         }
  106.     }
  107.     else
  108. #endif
  109.     {
  110.         pbuf = (DWORD *)shm->buffer;
  111.     }
  112.  
  113.     while (lpaintedtime < endtime)
  114.     {
  115.     // handle recirculating buffer issues
  116.         lpos = lpaintedtime & ((shm->samples>>1)-1);
  117.  
  118.         snd_out = (short *) pbuf + (lpos<<1);
  119.  
  120.         snd_linear_count = (shm->samples>>1) - lpos;
  121.         if (lpaintedtime + snd_linear_count > endtime)
  122.             snd_linear_count = endtime - lpaintedtime;
  123.  
  124.         snd_linear_count <<= 1;
  125.  
  126.     // write a linear blast of samples
  127.         Snd_WriteLinearBlastStereo16 ();
  128.  
  129.         snd_p += snd_linear_count;
  130.         lpaintedtime += (snd_linear_count>>1);
  131.     }
  132.  
  133. #ifdef _WIN32
  134.     if (pDSBuf)
  135.         pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
  136. #endif
  137. }
  138.  
  139. void S_TransferPaintBuffer(int endtime)
  140. {
  141.     int     out_idx;
  142.     int     count;
  143.     int     out_mask;
  144.     int     *p;
  145.     int     step;
  146.     int        val;
  147.     int        snd_vol;
  148.  
  149. #ifdef AMIGA
  150.     int    offset;
  151.     extern    int using_ahi;
  152.  
  153.     if (using_ahi) { /* using AHI, two 16-bit channels */
  154.  
  155.         short *out;
  156.         int val2;
  157.  
  158.         out = (short *)shm->buffer;
  159.         p = (int *) paintbuffer;
  160.         count = endtime - paintedtime;
  161.         out_mask = shm->samples - 1;
  162.         out_idx = (paintedtime << 1) & out_mask;
  163.         snd_vol = volume.value * 256;
  164.         while (count--) {
  165.  
  166.             val = (*p++ * snd_vol) >> 8;
  167.             if (val > 32767)
  168.                 val = 32767;
  169.             else if (val < -32768)
  170.                 val = -32768;
  171.  
  172.             val2 = (*p++ * snd_vol) >> 8;
  173.             if (val2 > 32767)
  174.                 val2 = 32767;
  175.             else if (val2 < -32768)
  176.                 val2 = -32768;
  177.  
  178.             *(int *)&out[out_idx] = (val << 16) | val2;
  179.  
  180.             out_idx = (out_idx + 2) & out_mask;
  181.  
  182.         }
  183.  
  184.     } else {    /* using audio.device, two 8-bit channels */
  185.  
  186. #define NEXTVAL                               \
  187.         val = (*p++ * snd_vol) >> 16; \
  188.         if (val > 127)                \
  189.             val = 127;            \
  190.         else if (val < -128)          \
  191.             val = -128
  192.  
  193.         p = (int *) paintbuffer;
  194.         count = endtime - paintedtime;
  195.         offset = shm->samples >> 1;
  196.         out_mask = offset - 1;
  197.         out_idx = paintedtime & out_mask;
  198.         snd_vol = volume.value * 256;
  199.         {
  200.             unsigned char *out = (unsigned char *)shm->buffer;
  201.             int lval1, lval2;
  202.             while ((out_idx & 3) != 0 && count > 0)
  203.             {
  204.                 NEXTVAL;
  205.                 out[out_idx] = val;
  206.     
  207.                 NEXTVAL;
  208.                 out[out_idx + offset] = val;
  209.     
  210.                 out_idx = (out_idx + 1) & out_mask;
  211.                 count--;
  212.             }
  213.             while (count >= 4)
  214.             {
  215.                 NEXTVAL;
  216.                 lval1 = val;
  217.                 NEXTVAL;
  218.                 lval2 = val;
  219.                 NEXTVAL;
  220.                 lval1 = (lval1 << 8) | (val & 255);
  221.                 NEXTVAL;
  222.                 lval2 = (lval2 << 8) | (val & 255);
  223.                 NEXTVAL;
  224.                 lval1 = (lval1 << 8) | (val & 255);
  225.                 NEXTVAL;
  226.                 lval2 = (lval2 << 8) | (val & 255);
  227.                 NEXTVAL;
  228.                 lval1 = (lval1 << 8) | (val & 255);
  229.                 NEXTVAL;
  230.                 lval2 = (lval2 << 8) | (val & 255);
  231.  
  232.                 *(int *)(&out[out_idx]) = lval1;
  233.                 *(int *)(&out[out_idx + offset]) = lval2;
  234.  
  235.                 out_idx = (out_idx + 4) & out_mask;
  236.  
  237.                 count -= 4;
  238.             }
  239.             while (count > 0)
  240.             {
  241.                 NEXTVAL;
  242.                 out[out_idx] = val;
  243.  
  244.                 NEXTVAL;
  245.                 out[out_idx + offset] = val;
  246.  
  247.                 out_idx = (out_idx + 1) & out_mask;
  248.                 count--;
  249.             }
  250.         }
  251.     }
  252. #else
  253.     DWORD    *pbuf;
  254. #ifdef _WIN32
  255.     int        reps;
  256.     DWORD    dwSize,dwSize2;
  257.     DWORD    *pbuf2;
  258.     HRESULT    hresult;
  259. #endif
  260.  
  261.     if (shm->samplebits == 16 && shm->channels == 2)
  262.     {
  263.         S_TransferStereo16 (endtime);
  264.         return;
  265.     }
  266.     
  267.     p = (int *) paintbuffer;
  268.     count = (endtime - paintedtime) * shm->channels;
  269.     out_mask = shm->samples - 1; 
  270.     out_idx = paintedtime * shm->channels & out_mask;
  271.     step = 3 - shm->channels;
  272.     snd_vol = volume.value*256;
  273.  
  274. #ifdef _WIN32
  275.     if (pDSBuf)
  276.     {
  277.         reps = 0;
  278.  
  279.         while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
  280.                                        &pbuf2,&dwSize2, 0)) != DS_OK)
  281.         {
  282.             if (hresult != DSERR_BUFFERLOST)
  283.             {
  284.                 Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
  285.                 S_Shutdown ();
  286.                 S_Startup ();
  287.                 return;
  288.             }
  289.  
  290.             if (++reps > 10000)
  291.             {
  292.                 Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
  293.                 S_Shutdown ();
  294.                 S_Startup ();
  295.                 return;
  296.             }
  297.         }
  298.     }
  299.     else
  300. #endif
  301.     {
  302.         pbuf = (DWORD *)shm->buffer;
  303.     }
  304.  
  305.     if (shm->samplebits == 16)
  306.     {
  307.         short *out = (short *) pbuf;
  308.         while (count--)
  309.         {
  310.             val = (*p * snd_vol) >> 8;
  311.             p+= step;
  312.             if (val > 0x7fff)
  313.                 val = 0x7fff;
  314.             else if (val < (short)0x8000)
  315.                 val = (short)0x8000;
  316.             out[out_idx] = val;
  317.             out_idx = (out_idx + 1) & out_mask;
  318.         }
  319.     }
  320.     else if (shm->samplebits == 8)
  321.     {
  322.         unsigned char *out = (unsigned char *) pbuf;
  323.         while (count--)
  324.         {
  325.             val = (*p * snd_vol) >> 8;
  326.             p+= step;
  327.             if (val > 0x7fff)
  328.                 val = 0x7fff;
  329.             else if (val < (short)0x8000)
  330.                 val = (short)0x8000;
  331.             out[out_idx] = (val>>8) + 128;
  332.             out_idx = (out_idx + 1) & out_mask;
  333.         }
  334.     }
  335.  
  336. #ifdef _WIN32
  337.     if (pDSBuf) {
  338.         DWORD dwNewpos, dwWrite;
  339.         int il = paintedtime;
  340.         int ir = endtime - paintedtime;
  341.         
  342.         ir += il;
  343.  
  344.         pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
  345.  
  346.         pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);
  347.  
  348. //        if ((dwNewpos >= il) && (dwNewpos <= ir))
  349. //            Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
  350.     }
  351. #endif
  352. #endif
  353. }
  354.  
  355.  
  356. /*
  357. ===============================================================================
  358.  
  359. CHANNEL MIXING
  360.  
  361. ===============================================================================
  362. */
  363.  
  364. void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
  365. void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
  366.  
  367. void S_PaintChannels(int endtime)
  368. {
  369.     int     i;
  370.     int     end;
  371.     channel_t *ch;
  372.     sfxcache_t    *sc;
  373.     int        ltime, count;
  374.  
  375.     while (paintedtime < endtime)
  376.     {
  377.     // if paintbuffer is smaller than DMA buffer
  378.         end = endtime;
  379.         if (endtime - paintedtime > PAINTBUFFER_SIZE)
  380.             end = paintedtime + PAINTBUFFER_SIZE;
  381.  
  382.     // clear the paint buffer
  383.         Q_memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
  384.  
  385.     // paint in the channels.
  386.         ch = channels;
  387.         for (i=0; i<total_channels ; i++, ch++)
  388.         {
  389.             if (!ch->sfx)
  390.                 continue;
  391.             if (!ch->leftvol && !ch->rightvol)
  392.                 continue;
  393.             sc = S_LoadSound (ch->sfx);
  394.             if (!sc)
  395.                 continue;
  396.  
  397.             ltime = paintedtime;
  398.  
  399.             while (ltime < end)
  400.             {    // paint up to end
  401.                 if (ch->end < end)
  402.                     count = ch->end - ltime;
  403.                 else
  404.                     count = end - ltime;
  405.  
  406.                 if (count > 0)
  407.                 {    
  408.                     if (sc->width == 1)
  409.                         SND_PaintChannelFrom8(ch, sc, count);
  410.                     else
  411.                         SND_PaintChannelFrom16(ch, sc, count);
  412.     
  413.                     ltime += count;
  414.                 }
  415.  
  416.             // if at end of loop, restart
  417.                 if (ltime >= ch->end)
  418.                 {
  419.                     if (sc->loopstart >= 0)
  420.                     {
  421.                         ch->pos = sc->loopstart;
  422.                         ch->end = ltime + sc->length - ch->pos;
  423.                     }
  424.                     else                
  425.                     {    // channel just stopped
  426.                         ch->sfx = NULL;
  427.                         break;
  428.                     }
  429.                 }
  430.             }
  431.                                                               
  432.         }
  433.  
  434.     // transfer out according to DMA format
  435.         S_TransferPaintBuffer(end);
  436.         paintedtime = end;
  437.     }
  438. }
  439.  
  440. void SND_InitScaletable (void)
  441. {
  442.     int        i, j;
  443.     
  444.     for (i=0 ; i<32 ; i++)
  445.         for (j=0 ; j<256 ; j++)
  446.             snd_scaletable[i][j] = ((signed char)j) * i * 8;
  447. }
  448.  
  449.  
  450. #if    !id386
  451.  
  452. void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
  453. {
  454.     int     data;
  455.     int        *lscale, *rscale;
  456.     unsigned char *sfx;
  457.     int        i;
  458.  
  459.     if (ch->leftvol > 255)
  460.         ch->leftvol = 255;
  461.     if (ch->rightvol > 255)
  462.         ch->rightvol = 255;
  463.         
  464.     lscale = snd_scaletable[ch->leftvol >> 3];
  465.     rscale = snd_scaletable[ch->rightvol >> 3];
  466.     sfx = (signed char *)sc->data + ch->pos;
  467.  
  468.     for (i=0 ; i<count ; i++)
  469.     {
  470.         data = sfx[i];
  471.         paintbuffer[i].left += lscale[data];
  472.         paintbuffer[i].right += rscale[data];
  473.     }
  474.     
  475.     ch->pos += count;
  476. }
  477.  
  478. #endif    // !id386
  479.  
  480.  
  481. void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
  482. {
  483.     int data;
  484.     int left, right;
  485.     int leftvol, rightvol;
  486.     signed short *sfx;
  487.     int    i;
  488.  
  489.     leftvol = ch->leftvol;
  490.     rightvol = ch->rightvol;
  491.     sfx = (signed short *)sc->data + ch->pos;
  492.  
  493.     for (i=0 ; i<count ; i++)
  494.     {
  495.         data = sfx[i];
  496.         left = (data * leftvol) >> 8;
  497.         right = (data * rightvol) >> 8;
  498.         paintbuffer[i].left += left;
  499.         paintbuffer[i].right += right;
  500.     }
  501.  
  502.     ch->pos += count;
  503. }
  504.  
  505.